/*
 * Copyright (c) 2010 All Inclusive Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.allinclusive.fw.database.dao.ibatis;

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.orm.ibatis.SqlMapClientCallback;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

import com.googlecode.allinclusive.fw.database.dao.SqlHolder;
import com.googlecode.allinclusive.fw.database.dao.UpdateDAO;
import com.ibatis.sqlmap.client.SqlMapExecutor;

/**
 * UpdateDAOインタフェースのiBATIS用実装クラス。
 *
 */
public class UpdateDAOiBatisImpl extends SqlMapClientDaoSupport implements
        UpdateDAO {
    /**
     * ログインスタンス
     */
    static Log log = LogFactory.getLog(UpdateDAOiBatisImpl.class);

    /**
     * 引数sqlIDで指定されたSQLを実行して、結果件数を返却する。
     * 実行するSQLは「insert, update delete」の3種類とする。
     *
     * @param sqlID 実行するSQLのID
     * @param bindParams SQLにバインドする値を格納したオブジェクト
     * @return SQLの実行結果件数を返却
     */
    public int execute(String sqlID, Object bindParams) {

        if (log.isDebugEnabled()) {
            log.debug("execute Start.");
        }

        //SqlMapClientの取得
        SqlMapClientTemplate sqlMapTemp = getSqlMapClientTemplate();

        // SQLの実行：データ追加。
        int row = sqlMapTemp.update(sqlID, bindParams);

        if (log.isDebugEnabled()) {
            log.debug("execute End.　success count:" + row);
        }
        return row;
    }

    /**
     * バッチ処理の実行メソッド。<br/>
     * 
     * 引数の{@link SqlHolder}のリストで指定されたすべてのSQLを実行する。<br/>
     * 
     * <br/>
     * <b>注意点</b><br/>
     * executeBatchはiBATISのバッチ実行機能を使用している。
     * executeBatchの戻り値は、実行したSQLによる変更行数が返却するが、
     * java.sql.PreparedStatementを使用しているため、
     * ドライバにより正確な行数が取得できないケースがある。<br/>
     * 変更行数が正確に取得できないドライバを使用する場合、
     * 変更行数がトランザクションに影響を与える業務では
     * (変更行数が0件の場合エラー処理をするケース等)、
     * バッチ更新は使用しないこと。<br/>
     * 参考資料）<br/>
     * <a href="http://otndnld.oracle.co.jp/document/products/oracle10g/101/doc_v5/java.101/B13514-02.pdf#page=450"
     * target="_blank">
     * http://otndnld.oracle.co.jp/document/products/oracle10g/101/doc_v5/java.101/B13514-02.pdf</a>
     * <br/>
     * 450ページ「標準バッチ処理のOracle 実装の更新件数」を参照のこと。<br/>
     * 
     * @param sqlHolders バッチ更新対象のsqlId、パラメータを格納した
     * SqlHolderインスタンスのリスト
     * @return SQLの実行結果件数
     */
    public int executeBatch(final List<SqlHolder> sqlHolders) {
        // SQLバッチ実行
        Integer result = 0;
        result = (Integer) getSqlMapClientTemplate().execute(
                new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor)
                  throws SQLException {
                StringBuilder logStr = new StringBuilder();
                if (log.isDebugEnabled()) {
                    log.debug("Batch SQL count:" + sqlHolders.size());
                }
                executor.startBatch();
                for (SqlHolder sqlHolder : sqlHolders) {
                    executor.update(
                        sqlHolder.getSqlID(), sqlHolder.getBindParams());
                    
                    if (log.isDebugEnabled()) {
                        logStr.setLength(0);
                        logStr.append("Call update sql. - SQL_ID:'");
                        logStr.append(sqlHolder.getSqlID());
                        logStr.append("' Parameters:");
                        logStr.append(sqlHolder.getBindParams());
                        log.debug(logStr.toString());
                    }
                }
                return executor.executeBatch();
            }
        });
        
        if (log.isDebugEnabled()) {
            log.debug("ExecuteBatch complete. Result:" + result);
        }
        return result.intValue();
    }
}
